/**
 * HTTP请求工具类
 * 基于uni.request封装，支持拦截器、错误处理、Token自动刷新
 */

import { mockUserAPI } from '@/mock/user'

// 配置信息
interface RequestConfig {
  baseURL: string
  timeout: number
  header: Record<string, string>
  useMock?: boolean
}

// 请求选项
interface RequestOptions {
  url?: string
  method?: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH'
  data?: any
  params?: Record<string, any>
  header?: Record<string, string>
  timeout?: number
  showLoading?: boolean
  loadingText?: string
  showError?: boolean
  skipAuth?: boolean  // 是否跳过认证头添加
}

// 响应数据
interface ApiResponse<T = any> {
  code: number
  message: string
  data: T
  timestamp: string
  requestId?: string
}

// 错误信息
interface ApiError {
  code: number
  message: string
  data?: any
}

class Request {
  private config: RequestConfig
  private refreshingToken = false
  private tokenRefreshQueue: Array<{ resolve: Function; reject: Function }> = []

  constructor() {
    // 从环境配置获取baseURL
    this.config = {
      baseURL: this.getBaseURL(),
      timeout: 10000,
      header: {
        'Content-Type': 'application/json'
      },
      useMock: false  // 关闭Mock模式，使用真实后端接口
    }
  }

  /**
   * 获取API基础URL
   */
  private getBaseURL(): string {
    // #ifdef H5
    if (process.env.NODE_ENV === 'development') {
      return 'http://127.0.0.1:8089'
    }
    return 'https://your-api-domain.com'
    // #endif

    // #ifdef MP-WEIXIN
    // 微信小程序开发环境暂时使用本地IP，需要配置为真实HTTPS域名
    // 注意：微信小程序要求使用HTTPS，且需要在微信公众平台配置服务器域名
    return 'http://127.0.0.1:8089'
    // #endif

    // #ifdef APP-PLUS
    return 'https://your-api-domain.com'
    // #endif

    return 'http://127.0.0.1:8089'
  }

  /**
   * 获取认证Token
   */
  private getToken(): string | null {
    try {
      const token = uni.getStorageSync('auth_token')
      // 清理可能存在的旧Token（带双引号的）
      if (token && token.startsWith('"') && token.endsWith('"')) {
        console.log('检测到旧格式Token，清除缓存')
        uni.removeStorageSync('auth_token')
        return null
      }
      return token
    } catch (error) {
      console.error('获取Token失败:', error)
      return null
    }
  }

  /**
   * 获取刷新Token
   */
  private getRefreshToken(): string | null {
    try {
      return uni.getStorageSync('refresh_token')
    } catch (error) {
      console.error('获取刷新Token失败:', error)
      return null
    }
  }

  /**
   * 设置Token
   */
  private setToken(token: string): void {
    try {
      uni.setStorageSync('auth_token', token)
    } catch (error) {
      console.error('设置Token失败:', error)
    }
  }

  /**
   * 构建完整URL
   */
  private buildURL(url: string, params?: Record<string, any>): string {
    const fullURL = url.startsWith('http') ? url : `${this.config.baseURL}${url}`

    if (!params) return fullURL

    const queryString = Object.entries(params)
      .filter(([_, value]) => value !== undefined && value !== null)
      .map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`)
      .join('&')

    return queryString ? `${fullURL}?${queryString}` : fullURL
  }

  /**
   * 构建请求头
   */
  private buildHeader(customHeader?: Record<string, string>, skipAuth: boolean = false): Record<string, string> {
    const header = { ...this.config.header, ...customHeader }

    // 添加认证Token（除非明确跳过）
    if (!skipAuth) {
      const token = this.getToken()
      if (token) {
        header['Authorization'] = `Bearer ${token}`
      }
    }

    return header
  }

  /**
   * 显示加载提示
   */
  private showLoading(text: string = '加载中...'): () => void {
    uni.showLoading({
      title: text,
      mask: true
    })
    return () => uni.hideLoading()
  }

  /**
   * 显示错误提示
   */
  private showError(message: string): void {
    // 确保message不为空
    const displayMessage = message || '操作失败'

    uni.showToast({
      title: displayMessage,
      icon: 'none',
      duration: 3000
    })
  }

  /**
   * 处理响应错误
   */
  private handleResponseError(response: any): ApiError {
    const { statusCode, data } = response

    // HTTP状态码错误
    if (statusCode !== 200) {
      return {
        code: statusCode,
        message: this.getHttpStatusMessage(statusCode)
      }
    }

    // 业务错误
    if (data && typeof data === 'object') {
      return {
        code: data.code || statusCode,
        message: data.message || '请求失败',
        data: data.data
      }
    }

    return {
      code: statusCode,
      message: '请求失败'
    }
  }

  /**
   * 获取HTTP状态码对应的消息
   */
  private getHttpStatusMessage(status: number): string {
    const messages: Record<number, string> = {
      400: '请求参数错误',
      401: '未授权，请重新登录',
      403: '禁止访问',
      404: '请求的资源不存在',
      405: '请求方法不被允许',
      408: '请求超时',
      429: '请求过于频繁，请稍后再试',
      500: '服务器内部错误',
      502: '网关错误',
      503: '服务不可用',
      504: '网关超时'
    }

    return messages[status] || '网络错误'
  }

  /**
   * 刷新Token
   */
  private async refreshToken(): Promise<boolean> {
    if (this.refreshingToken) {
      // 如果正在刷新，加入队列等待
      return new Promise((resolve, reject) => {
        this.tokenRefreshQueue.push({ resolve, reject })
      })
    }

    this.refreshingToken = true
    const refreshToken = this.getRefreshToken()

    if (!refreshToken) {
      this.clearTokens()
      this.refreshingToken = false
      return false
    }

    try {
      const response = await this.uniRequest({
        url: '/api/v1/auth/refresh',
        method: 'POST',
        data: { refreshToken },
        header: { 'Content-Type': 'application/json' },
        showLoading: false,
        skipAuth: true,  // 刷新Token请求不需要Authorization头
        showError: false
      })

      const { data } = response as ApiResponse<{ token: string; expiresIn: number }>

      if (data.token) {
        this.setToken(data.token)

        // 通知队列中的请求
        this.tokenRefreshQueue.forEach(({ resolve }) => resolve(true))
        this.tokenRefreshQueue = []

        return true
      }

      return false
    } catch (error) {
      console.error('Token刷新失败:', error)

      // 通知队列中的请求失败
      this.tokenRefreshQueue.forEach(({ reject }) => reject(error))
      this.tokenRefreshQueue = []

      this.clearTokens()
      return false
    } finally {
      this.refreshingToken = false
    }
  }

  /**
   * 清除所有Token
   */
  private clearTokens(): void {
    try {
      uni.removeStorageSync('auth_token')
      uni.removeStorageSync('refresh_token')
      uni.removeStorageSync('user_info')
      uni.removeStorageSync('login_time')
      uni.removeStorageSync('expires_in')
    } catch (error) {
      console.error('清除Token失败:', error)
    }
  }

  /**
   * 检查是否需要跳转到登录页
   */
  private shouldRedirectToLogin(error: ApiError): boolean {
    return error.code === 401 || error.code === 1002 // 1002为Token过期错误码
  }

  /**
   * 核心请求方法
   */
  private async uniRequest<T = any>(options: RequestOptions): Promise<ApiResponse<T>> {
    const {
      url = '',
      method = 'GET',
      data,
      params,
      header,
      timeout = this.config.timeout,
      showLoading: shouldShowLoading = true,
      loadingText = '加载中...',
      showError: shouldShowError = true,
      skipAuth = false
    } = options

    let hideLoading: (() => void) | null = null

    try {
      // 显示加载提示
      if (shouldShowLoading) {
        hideLoading = this.showLoading(loadingText)
      }

      // 检查是否使用Mock数据
      if (this.config.useMock && url.startsWith('/api/users')) {
        console.log('使用Mock数据:', { url, method, data, params })
        return this.handleMockRequest<T>(url, method, data, params)
      }

      // 构建请求配置
      const requestConfig: UniApp.RequestOptions = {
        url: this.buildURL(url, params),
        method: method as any, // 类型转换，兼容uni-app的method类型
        data,
        header: this.buildHeader(header, skipAuth),
        timeout,
        success: (response) => response,
        fail: (error) => {
          throw new Error(error.errMsg || '网络请求失败')
        }
      }

      // 发起请求
      const response = await new Promise<UniApp.RequestSuccessCallbackResult>((resolve, reject) => {
        requestConfig.success = (res) => {
          console.log('请求成功响应:', res)
          resolve(res)
        }
        requestConfig.fail = (error) => {
          console.error('请求失败:', error)
          const enhancedError = new Error(error.errMsg || '网络请求失败')
          Object.assign(enhancedError, error)
          reject(enhancedError)
        }
        uni.request(requestConfig)
      })

      // 检查响应
      const { statusCode, data: responseData } = response

      console.log('响应状态码:', statusCode)
      console.log('响应数据:', responseData)

      if (statusCode !== 200) {
        throw this.handleResponseError(response)
      }

      // 处理空响应数据
      if (!responseData || typeof responseData !== 'object') {
        throw new Error('服务器响应数据格式错误')
      }

      const apiResponse = responseData as ApiResponse<T>

      // 检查业务状态码 (兼容后端返回0和200两种情况)
      if (apiResponse.code !== 200 && apiResponse.code !== 0) {
        const error = {
          code: apiResponse.code,
          message: apiResponse.message,
          data: apiResponse.data
        } as ApiError

        // 处理Token过期
        if (this.shouldRedirectToLogin(error)) {
          // 尝试刷新Token
          const refreshSuccess = await this.refreshToken()

          if (refreshSuccess) {
            // Token刷新成功，重新发起请求
            return this.uniRequest<T>(options)
          } else {
            // Token刷新失败，跳转到登录页
            this.clearTokens()
            uni.reLaunch({
              url: '/pages/auth/login'
            })
            throw error
          }
        }

        throw error
      }

      return apiResponse
    } catch (error) {
      const apiError = error as ApiError

      // 显示错误提示
      if (shouldShowError) {
        this.showError(apiError.message)
      }

      throw apiError
    } finally {
      // 隐藏加载提示
      if (hideLoading) {
        hideLoading()
      }
    }
  }

  /**
   * 处理Mock请求
   */
  private async handleMockRequest<T = any>(url: string, method: string, data?: any, params?: any): Promise<ApiResponse<T>> {
    console.log('处理Mock请求:', { url, method, data, params })

    // 用户相关接口
    if (url === '/api/users') {
      if (method === 'GET') {
        return await mockUserAPI.getUsers(params) as ApiResponse<T>
      } else if (method === 'POST') {
        return await mockUserAPI.createUser(data) as ApiResponse<T>
      }
    }

    // 单个用户操作
    if (url.startsWith('/api/users/') && !url.includes('/batch')) {
      const userId = url.split('/').pop()

      if (method === 'GET') {
        return await mockUserAPI.getUserById(userId!) as ApiResponse<T>
      } else if (method === 'PUT') {
        return await mockUserAPI.updateUser(userId!, data) as ApiResponse<T>
      } else if (method === 'DELETE') {
        return await mockUserAPI.deleteUser(userId!) as ApiResponse<T>
      }
    }

    // 密码重置
    if (url.includes('/reset-password')) {
      const userId = url.split('/')[3]
      return await mockUserAPI.resetUserPassword(userId!, data.newPassword) as ApiResponse<T>
    }

    // 用户激活/禁用
    if (url.includes('/activate')) {
      const userId = url.split('/')[3]
      return await mockUserAPI.activateUser(userId!) as ApiResponse<T>
    }

    if (url.includes('/deactivate')) {
      const userId = url.split('/')[3]
      return await mockUserAPI.deactivateUser(userId!) as ApiResponse<T>
    }

    // 批量操作
    if (url.includes('/batch-update-status')) {
      return await mockUserAPI.batchUpdateUserStatus(data.userIds, data.status) as ApiResponse<T>
    }

    if (url.includes('/batch-delete')) {
      return await mockUserAPI.batchDeleteUsers(data.userIds) as ApiResponse<T>
    }

    // 按角色获取用户
    if (url.includes('/role/')) {
      const role = url.split('/').pop()
      return await mockUserAPI.getUsersByRole(role!) as ApiResponse<T>
    }

    // 按状态获取用户
    if (url.includes('/status/')) {
      const status = url.split('/').pop()
      return await mockUserAPI.getUsersByStatus(status!) as ApiResponse<T>
    }

    throw new Error(`Mock接口未实现: ${method} ${url}`)
  }

  /**
   * GET请求
   */
  get<T = any>(url: string, params?: Record<string, any>, options?: Partial<RequestOptions>): Promise<ApiResponse<T>> {
    return this.uniRequest<T>({
      url,
      method: 'GET',
      params: params || {},
      ...options
    })
  }

  /**
   * POST请求
   */
  post<T = any>(url: string, data?: any, options?: Partial<RequestOptions>): Promise<ApiResponse<T>> {
    return this.uniRequest<T>({
      url,
      method: 'POST',
      data,
      ...options
    })
  }

  /**
   * PUT请求
   */
  put<T = any>(url: string, data?: any, options?: Partial<RequestOptions>): Promise<ApiResponse<T>> {
    return this.uniRequest<T>({
      url,
      method: 'PUT',
      data,
      ...options
    })
  }

  /**
   * DELETE请求
   */
  delete<T = any>(url: string, params?: Record<string, any>, options?: Partial<RequestOptions>): Promise<ApiResponse<T>> {
    return this.uniRequest<T>({
      url,
      method: 'DELETE',
      params: params || {},
      ...options
    })
  }

  /**
   * 通用请求方法
   */
  request<T = any>(options: RequestOptions): Promise<ApiResponse<T>> {
    return this.uniRequest<T>(options)
  }

  /**
   * PATCH请求
   */
  patch<T = any>(url: string, data?: any, options?: Partial<RequestOptions>): Promise<ApiResponse<T>> {
    return this.uniRequest<T>({
      url,
      method: 'PATCH',
      data,
      ...options
    })
  }

  /**
   * 文件上传
   */
  upload<T = any>(url: string, filePath: string, formData?: Record<string, any>, options?: {
    name?: string
    header?: Record<string, string>
    showLoading?: boolean
    loadingText?: string
    showError?: boolean
  }): Promise<ApiResponse<T>> {
    const {
      name = 'file',
      header,
      showLoading: shouldShowLoading = true,
      loadingText = '上传中...',
      showError: shouldShowError = true
    } = options || {}

    let hideLoading: (() => void) | null = null

    return new Promise((resolve, reject) => {
      try {
        // 显示加载提示
        if (shouldShowLoading) {
          hideLoading = this.showLoading(loadingText)
        }

        uni.uploadFile({
          url: this.buildURL(url),
          filePath,
          name,
          formData,
          header: this.buildHeader(header),
          success: (response) => {
            try {
              const data = JSON.parse(response.data) as ApiResponse<T>

              if (data.code === 200) {
                resolve(data)
              } else {
                const error = {
                  code: data.code,
                  message: data.message,
                  data: data.data
                } as ApiError

                if (shouldShowError) {
                  this.showError(error.message)
                }

                reject(error)
              }
            } catch (parseError) {
              const error = {
                code: -1,
                message: '响应数据解析失败'
              } as ApiError

              if (shouldShowError) {
                this.showError(error.message)
              }

              reject(error)
            }
          },
          fail: (error) => {
            const apiError = {
              code: -1,
              message: error.errMsg || '上传失败'
            } as ApiError

            if (shouldShowError) {
              this.showError(apiError.message)
            }

            reject(apiError)
          },
          complete: () => {
            // 隐藏加载提示
            if (hideLoading) {
              hideLoading()
            }
          }
        })
      } catch (error) {
        const apiError = {
          code: -1,
          message: '上传失败'
        } as ApiError

        if (shouldShowError) {
          this.showError(apiError.message)
        }

        reject(apiError)
      }
    })
  }

  /**
   * 设置请求配置
   */
  setConfig(config: Partial<RequestConfig>): void {
    this.config = { ...this.config, ...config }
  }

  /**
   * 获取当前配置
   */
  getConfig(): RequestConfig {
    return { ...this.config }
  }
}

// 创建实例
const request = new Request()

export default request
export type { RequestConfig, RequestOptions, ApiResponse, ApiError }